#ifndef _UESCRIPT_
#define _UESCRIPT_

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <io.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <stdarg.h>
#include <sys/stat.h>

#define FALSE 0
#define TRUE 1
#define BOOL int

#pragma warning(disable:4996)

#define UES_SUCCESS			1
#define UES_FAIL			0
#define UES_FUNCTION_C		1
#define UES_FUNCTION_SCR	2
#define MAX_UES_FUNCTIONS	65536
#define UES_COMNTTYPE_SNGL	1
#define UES_COMNTTYPE_MULT	2
#define UES_ENV_CORE		0
#define UES_ROOTAREA		0
#define UES_MAXFUNCNAME		256
#define UES_MAXARGS			256
#define UES_MAX_DEFS_PER_AREA	256
#define UES_MAX_AREAS		256
#define UES_MAX_ARRAY_DIM	16
#define	UES_MEM_DEFAULT_BEGIN	0x10000000
#define UES_BINARY_MAXSIZE	500000
enum
{
	UES_NOSTRING,
	UES_DEFSTRING,
	UES_SPCSTRING
};
// SYMBOLS
#define UES_SCRIPT_SEP		';'
#define UES_ARGS_SEP		','
#define UES_FUNCSPEC_IN		'('
#define UES_FUNCSPEC_OUT	')'
#define UES_ARRAYSPEC_IN	'['
#define UES_ARRAYSPEC_OUT	']'
#define UES_COMNTFLAG_SNGL	"//"
#define UES_CMNTFLAG_M_IN	"/*"
#define UES_CMNTFLAG_M_OUT	"*/"
#define UES_AREA_IN			'{'
#define UES_AREA_OUT		'}'
#define UES_SET				'='
#define UES_STR_IN_1		'"'
#define UES_STR_OUT_1		'"'
#define UES_STR_IN_2		'\''
#define UES_STR_OUT_2		'\''
#define UES_CMDEND			';'
#define UES_DEFSTRING_IN	'"'
#define UES_DEFSTRING_OUT	'"'
#define UES_SPCSTRING_IN	'\''
#define UES_SPCSTRING_OUT	'\''
#define UES_SPCSYMBCHR		'\\'
#define UES_CONTINUESTR		UES_SPCSYMBCHR
#define	UES_ADD				'+'
#define UES_SUBSTRACT		'-'
#define UES_DIVIDE			'/'
#define UES_MULTIPLY		'*'
#define UES_BINARY_RIGHT	">>"
#define UES_BINARY_LEFT		"<<"
// OPCODES
#define OPCODE_MOVE			1
#define OPCODE_CALL			2
#define OPCODE_RETURN		3
#define OPCODE_JUMPIFTRUE	4
#define	OPCODE_JUMPIFFALSE	5
#define OPCODE_JUMP			6
#define OPCODE_ADD			7
#define OPCODE_SUBSTRACT	8
#define OPCODE_MULTIPLY		9
#define OPCODE_DIVIDE		10
#define OPCODE_XOR			13
#define OPCODE_CDQ			14
#define OPCODE_JMP			15
#define OPCODE_JMP_E		16
#define OPCODE_JMP_NE		17
#define OPCODE_JMP_G		18
#define OPCODE_JMP_GE		19
#define OPCODE_JMP_L		20
#define OPCODE_JMP_LE		21
#define OPCODE_CMP			22
#define OPCODE_NEG			23
#define OPCODE_DIVSS		24
#define OPCODE_PUSHFSTACK	25
#define OPCODE_POPFSTACK	26
#define OPCODE_FLT_JMP		27
#define OPCODE_FLT_JMP_E	28
#define OPCODE_FLT_JMP_NE	29
#define OPCODE_FLT_JMP_G	30
#define OPCODE_FLT_JMP_GE	31
#define OPCODE_FLT_JMP_L	32
#define OPCODE_FLT_JMP_LE	33
// - NOTE: POW and SQRT will be lib functions
#define OPCODE_PUSH			11	// Push object on stack
#define OPCODE_POP			12	// Set stuff into memory
// OPCODE_CALC AND COND METHODS
#define	CALC_ADD			1
#define CALC_SUBTRACT		2
#define CALC_MULTIPLY		3
#define CALC_DIVIDE			4
#define CALC_MODULO			5
#define CALC_EQUAL			6
#define CALC_AND			7
#define CALC_OR				8
#define CALC_XOR			9
#define CALC_SQRT			10
#define CALC_POW			11

#define	UES_ARGTYPE_FUNC	1
#define	UES_ARGTYPE_ARRAY	2

// X86 Opcodes
#define X86_ADD_MEM_REGISTER	0x01
#define X86_ADD_REGISTER		0x03
#define X86_CONDITIONAL_OP		0x0F
#define X86_SUB_MEM_REGISTER	0x29
#define	X86_SUB_REGISTER		0x2B
#define X86_CMP					0x3B
#define X86_PUSH_EAX			0x50
#define X86_PUSH_ECX			0x51
#define X86_PUSH_EDX			0x52
#define X86_PUSH_EBX			0x53
#define X86_PUSH_ESP			0x54
#define X86_PUSH_EBP			0x55
#define	X86_PUSH_ESI			0x56
#define	X86_PUSH_EDI			0x57
#define X86_POP_EAX				0x58
#define X86_POP_ECX				0x59
#define X86_POP_EDX				0x5A
#define X86_POP_EBX				0x5B
#define X86_POP_ESP				0x5C
#define X86_POP_EBP				0x5D
#define X86_POP_ESI				0x5E
#define X86_POP_EDI				0x5F
#define X86_CALC_MEMORY_WORD	0x66
#define	X86_CALC_MEMORY_BYTE	0x80
#define	X86_CALC_MEMORY_DWORD	0x81
#define X86_CALC_REG_INT		0x81
#define X86_MOV_REG_REG			0x8B
#define	X86_PUSH_CONST_BYTE		0x6A
#define X86_PUSH_CONST_WORD		0x69
#define X86_PUSH_CONST_DWORD	0x68
#define X86_MOV_MEM_REGISTER	0x89
#define X86_MOV_REGISTER_MEM	0x8B
#define	X86_CDQ					0x99
#define X86_MOV_EAX				0xB8
#define	X86_MOV_ECX				0xB9
#define X86_MOV_EDX				0xBA
#define X86_MOV_EBX				0xBB
#define X86_MOV_ESI				0xBE
#define X86_RETURN				0xC3
#define X86_MOV_PREGISTER_MEM	0xC7
#define X86_FLOAT_LOAD			0xD9
#define X86_FLOAT_CALC			0xD8
#define	X86_CALL				0xE8
#define X86_JMP_DWORD			0xE9
#define X86_IDIV				0xF7
#define X86_CALL_FAR			0xFF
#define X86_PUSH_PREG			0xFF

// SSE Opcodes
#define SSE_ID					0x0FF3
#define SSE_MOV_REG_MEM			0x10
#define SSE_MOV_MEM_REG			0x11
#define SSE_ADDSS				0x58
#define SSE_MULSS				0x59
#define SSE_SUBSS				0x5C
#define SSE_DIVSS				0x5E

// SSE movement variants
#define SSE_MOV_XMM0_MEM		0x05
#define SSE_MOV_XMM1_MEM		0x0D
#define SSE_MOV_XMM0_XMM1		0xC1
#define SSE_MOV_XMM0_XMM2		0xC2
#define SSE_MOV_XMM1_XMM0		0xC8
#define SSE_MOV_XMM1_XMM2		0xCA
#define SSE_MOV_XMM2_XMM0		0xD0
#define SSE_MOV_XMM2_XMM1		0xD1

// CALL FAR variants
#define X86_CALL_FAR_MEM		0x15

// Calc defines
#define	X86_CALC_ADD_MEMORY		0x05
#define X86_CALC_MUL_MEMORY		0x0D
#define X86_CALC_FSUB_MEMORY	0x25
#define	X86_CALC_SUB_MEMORY		0x2D
#define	X86_CALC_FDIV_MEMORY	0x35
#define X86_CALC_DIV_MEMORY		0x3D
#define	X86_CALC_SUB_STACK		0x6D
#define X86_CALC_ADD_EAX		0xC0
#define X86_CALC_ADD_ECX		0xC1
#define	X86_CALC_ADD_EDX		0xC2
#define	X86_CALC_ADD_EBX		0xC3
#define	X86_CALC_ADD_ESP		0xC4
#define	X86_CALC_ADD_EBP		0xC5
#define	X86_CALC_ADD_ESI		0xC6
#define	X86_CALC_ADD_EDI		0xC7
#define X86_CALC_EAX_EDI		0xC7
#define X86_CALC_EAX_ECX		0xC1
#define X86_CALC_EAX_EDX		0xC2
#define X86_CALC_EAX_ESI		0xC6
#define X86_CALC_ECX_EAX		0xC8
#define X86_CALC_ECX_EDX		0xCA
#define X86_CALC_ECX_EBX		0xCB
#define X86_CALC_EBX_EAX		0xD8
#define X86_CALC_EBX_ECX		0xD9
#define X86_CALC_EBX_EDX		0xDA
#define X86_CALC_EBX_EBX		0xDB
#define X86_CALC_EBX_ESI		0xDE
#define	X86_CALC_SUB_EAX		0xE8
#define	X86_CALC_SUB_ECX		0xE9
#define	X86_CALC_SUB_EDX		0xEA
#define	X86_CALC_SUB_EBX		0xEB
#define	X86_CALC_SUB_ESP		0xEC
#define	X86_CALC_SUB_EBP		0xED
#define	X86_CALC_SUB_ESI		0xEE
#define	X86_CALC_SUB_EDI		0xEF
#define X86_DIV_EAX_EAX			0xF8
#define X86_DIV_EAX_ESI			0xFE

// Register ids
#define X86_REGISTER_EAX		0x05
#define X86_REGISTER_ECX		0x0D
#define X86_REGISTER_EDX		0x15
#define	X86_REGISTER_EBX		0x1D
#define X86_REGISTER_ESP		0x25
#define X86_REGISTER_ESI		0x35

// Offset registers
#define X86_REGISTER_PEAX		0x30
#define X86_REGISTER_PECX		0x31
#define X86_REGISTER_PEDX		0x32
#define X86_REGISTER_PEBX		0x33
#define X86_REGISTER_PESI		0x36

// Movement stuff
#define X86_MOV_PEAX_EAX	0x00
#define X86_MOV_PECX_EAX	0x01
#define X86_MOV_PEDX_EAX	0x02
#define X86_MOV_PEBX_EAX	0x03
#define X86_MOV_PECX_EBX	0x19
#define X86_MOV_PEDX_EBX	0x1A
#define X86_MOV_PESI_EAX	0x06
#define X86_MOV_PESI_EBX	0x1E
#define X86_MOV_PESI_MEM	0x06
#define X86_MOV_EDX_PEAX	0x10
#define X86_MOV_EDX_PECX	0x11
#define X86_MOV_EDX_PEDX	0x12
#define X86_MOV_EDX_PEBX	0x13
#define X86_MOV_EDX_PESI	0x16
#define X86_MOV_EAX_EAX		0xC0
#define X86_MOV_EAX_EBX		0xC3
#define X86_MOV_EAX_ESI		0xC6
#define X86_MOV_EAX_EDI		0xC7
#define X86_MOV_EDX_EAX		0xD0
#define X86_MOV_EDX_ECX		0xD1
#define X86_MOV_EDX_EBX		0xD3
#define X86_MOV_EDX_ESI		0xD6
#define X86_MOV_EBX_EAX		0xD8
#define X86_MOV_ESP_EBP		0xE5
#define X86_MOV_EBP_ESP		0xEC
#define X86_MOV_ESI_EAX		0xF0

// Float load
#define X86_FLOAT_ST0_MEM	0x05
#define	X86_FLOAD_ST0_ST1	0xE8

// Conditional ops
#define X86_COND_JMP_E		0x84
#define X86_COND_JMP_NE		0x85
#define X86_COND_JMP_L		0x8C
#define X86_COND_JMP_GE		0x8D
#define X86_COND_JMP_LE		0x8E
#define X86_COND_JMP_G		0x8F

// Registers
enum
{
	REGISTER_AL,
	REGISTER_AH,
	REGISTER_AX,
	REGISTER_BL,
	REGISTER_BH,
	REGISTER_BX,
	REGISTER_CL,
	REGISTER_CH,
	REGISTER_CX,
	REGISTER_DL,
	REGISTER_DH,
	REGISTER_DX,

	REGISTER_DI,
	REGISTER_SI,
	REGISTER_SP,
	REGISTER_BP,
	REGISTER_XMM0,
	REGISTER_XMM1,
	REGISTER_XMM2,
	REGISTER_XMM3,
	REGISTER_XMM4,
	NUM_REGISTER
};

#define REGISTER_SSE_START REGISTER_BP

// Setups a listitem
#define LIST_SETUP(strct) struct strct *prev; struct strct *next;
// LIST handling
#define	LIST_CLEAR(list)		{ (list)->next=(list);(list)->prev=(list); }
#define	LIST_APPEND(list,item)	{ (item)->next=(list);(item)->prev=(list)->prev;(item)->prev->next=(item);(item)->next->prev=(item); }
#define	LIST_INSERT(list,item)	{ (item)->next=(list)->next;(item)->prev=(list);(item)->prev->next=(item);(item)->next->prev=(item); }
#define	LIST_REMOVE(item)		{ (item)->prev->next=(item)->next;(item)->next->prev=(item)->prev;(item)->next=(item);(item)->prev=(item); }
#define	LIST_EMPTY (list)		{ ((list)->next=(list))?TRUE:FALSE }
#define LIST_GETTAIL(list,tail)	{ (tail)=(list);while((tail)!=(list))(tail)=(list)->next;(tail)=(tail)->prev; }
#define	LIST_FOREACH_BEGIN(list,lpVoid)	(lpVoid)=(list);while(((lpVoid)=(lpVoid)->next)!=(list)) {
#define	LIST_FOREACH_END(list,lpVoid)	}

// Header for every memoryentry
typedef struct ues_memheader_s
{
	unsigned char tag;
#ifdef _DEBUG
	size_t memsize;
	LIST_SETUP(ues_memheader_s)
#endif
} ues_memheader_t;

#include "uesmemory.h"
#include "uesobject.h"

enum eAllocTags
{
	TAG_TXTBUFF,
	TAG_OBJECT,
	TAG_OBJECTMEM,
	TAG_MEMARRANGE,
	TAG_CONVERTOBJ,
	TAG_CONVERTOBJMEM,
	TAG_OPCODE,
	TAG_PROGSTRING,
	TAG_ARGAREA,
	TAG_CLASS,
	NUM_TAGS
};

#if (NUM_TAGS > TAG_LAST)
#error "Too many custom tags specified!"
#endif

// Opcode Memory
typedef struct ues_op_s
{
	unsigned char opcode;					// Operation to be cast
	void *data[3];
	unsigned char datasize;					// Size of data
	int boffset;							// Position of opcode begin
	int offset;								// Position of this opcode for future jmp allocations

	//struct ues_op_s *call;		// Opcode to return at return to
	LIST_SETUP(ues_op_s)
} ues_op_t;

// Argument of functions, struct
typedef struct ues_var_s
{
	ues_mem_t *mem;
	unsigned char *name;													// Identify
} ues_var_t;
typedef struct ues_var_s ues_arg_t;

// Argumental area
typedef struct ues_argarea_s
{
	unsigned char numArgs;
	ues_mem_t *args[UES_MAXARGS];
	unsigned char *names[UES_MAXARGS];
} ues_argarea_t;

// Function memory
typedef struct ues_function_s
{
	void *data;													// Begin of data
	unsigned char *name;													// To identify
	unsigned char retCast;											// Cast of the returned value
	int iID;														// Parameter of return cast, used by struct and single def
	unsigned char retIsAlloced;
	ues_argarea_t *retArgs;											// Argumental area parse of return function

	unsigned char type;
	// Function stuff
	//unsigned int numArgs;												// Number of arguments this function needs
	//ues_mem_t *args[UES_MAXARGS];
	ues_argarea_t *args;
} ues_function_t;

// Area
typedef struct ues_area_s
{
	unsigned int id;

	unsigned int numDefs;
	ues_var_t *defs[UES_MAX_DEFS_PER_AREA];

	struct ues_area_s *parrent;
} ues_area_t;

// Struct to transfer defs with
typedef struct ues_def_data_s
{
	ues_function_t *func;
	unsigned short argc;
	ues_arg_t **argv;
} ues_def_data_t;

// Memory in mem_arrange
typedef struct ues_mem_alloc_s
{
	ues_mem_t *dflt;
	unsigned char *name;					// Name id
	LIST_SETUP(ues_mem_alloc_s)
} ues_mem_alloc_t;

#define UES_PRIORITY_IGNORE	0
#define UES_PRIORITY_SET	1
#define UES_PRIORITY_LOW	2
#define UES_PRIORITY_MEDIUM	3
#define UES_PRIORITY_HIGH	4

// List up special chars
typedef struct ues_spcsymb_s
{
	unsigned char *symb;
	//unsigned int function;		// What shall this char do?
	unsigned int priority;
} ues_spcsymb_t;

// Objects for easier compiler procession
typedef struct ues_obj_s
{
	unsigned char type;
	unsigned char *def;
} ues_obj_t;

// Jumptable to use for later jmp locations
typedef struct ues_jump_s
{
	unsigned char ucActive;
	ues_op_t *jmpop;
	ues_op_t *jmpto;
} ues_jump_t;


/*================================

	Structure UES Definition

	There shall be two types of definitions in UES.
	One type is the struct definition which I handle here.
	It contains of more members, which all have their name to access them during compilation.
	Those make a direct row of units, who sum up to a struct.
	The UES strust is, just like the C struct, a compilation of data to be used in context.

================================*/
#define MAX_UES_STRUCTS 256

typedef struct ues_struct_s
{
	char *sDefName;								// Name of this definition
	ues_argarea_t defs;							// All members of this struct
	size_t sSize;								// Size of this struct
	int iStructID;								// ID of the struct, for fast procession
} ues_struct_t;

/*==================================

	Single UES Definition

	To be made not too complex, I divided this definition section into two parts.
	The first part is discussed above, now we turn to the single definition.
	This is a definition of one member, just like "int", "string" or "float".
	Actually, those shall be redirects for clearification and safety.

===================================*/
#define MAX_UES_SINGLE_DEFS	2047
#define UES_MAX_BINARIES	2047

typedef struct ues_def_s
{
	char *sDefName;
	unsigned char ucType;						// The static type of the definition
} ues_def_t;

/*================================

	UES Table

	A table in UES is a static or dynamic listing of elements.
	Tables can be dynamic, unlike in C, but then cant be given as arguments.

================================*/
typedef struct ues_array_s
{
	unsigned char isDynamic;					// Dynamic?
	ues_mem_t *nElements;						// If not dynamic, number of elements
	unsigned char cast;							// Cast of every element in this array
	void *castData;								// Probably there are more parameters needed
	ues_mem_t *sizeElement;						// Generated size of element
	void *data;									// The data the elements will be saved at
} ues_array_t;

// Class for compiled data, package of binary
typedef struct ues_bin_s
{
	void *pEnv;									// Environmental link
	ues_mem_alloc_t *comp_mem;					// Memory of compiled data
	ues_struct_t structs[MAX_UES_STRUCTS];		// Structure definitions of this binary
	unsigned int nStructs;
	void (*pCode)();							// Compiled code
	ues_mem_t registers[NUM_REGISTER];			// Registers
	ues_mem_t offset_registers[NUM_REGISTER];	// Registers to be used as offsets [dword ptr]

	// Important function mems
	ues_mem_t	*pMALLOC;
	ues_mem_t	*pFREE;
	ues_mem_t	*pSTRLEN;
	ues_mem_t	*pMEMCPY;

	ues_mem_t	*lparam;
} ues_bin_t;

// Environment of a compilation or its compiled members
typedef struct ues_env_s
{
	ues_mem_alloc_t *memory;					// Global memory
	ues_struct_t structs[MAX_UES_STRUCTS];		// Structure definitions
	unsigned int nStructs;
	ues_def_t defs[MAX_UES_SINGLE_DEFS];		// Single definitions
	unsigned int nDefs;
	ues_bin_t *binaries[UES_MAX_BINARIES];
	unsigned int nBinaries;
} ues_env_t;

typedef int (*ues_funccast_t)(ues_function_t *data, unsigned char argc, ues_arg_t *argv);

#define OPCODE		ues_op_t
#define FUNCTION	ues_function_t

// Memory management
ues_mem_alloc_t*	UES_Mem_Construct();
// Init
unsigned char	UES_InitFunction(void *ptr, const char *name, ues_env_t *env, unsigned char retCast, int iID, ues_argarea_t *retArgs, ues_argarea_t *args);
void			UES_PrintMemoryUsage();
void*			UES_Load(unsigned char *filename, ues_env_t *env);
void			UES_FreeBinaryByCode(ues_env_t *pEnv, void *pCode);
void			UES_FreeEnvironment(ues_env_t *pEnv);
ues_argarea_t*	UES_CreateArgumentalArea(unsigned char numArgs, ...);
ues_env_t*		UES_CreateEnvironment();
// UES Functions
int				UES_CreateStruct(ues_env_t *pEnv, char *sDefName, unsigned char numArgs, ...);
int				UES_CreateSingleDef(ues_env_t *pEnv, char *sDefName, unsigned char ucType);
int				UES_GetStructByName(ues_env_t *pEnv, char *sDefName);
int				UES_GetBinaryStructByName(ues_bin_t *pBin, char *sDefName);
int				UES_GetBinaryStructByNameEx(ues_bin_t *pBin, char *sDefName, size_t sLen);
int				UES_GetSingleDefByName(ues_env_t *pEnv, char *sDefName);
int				UES_GetSingleDefByNameEx(ues_env_t *pEnv, char *sDefName, size_t sLen);
ues_function_t*	UES_GetFunctionByHash(unsigned int hash);
unsigned char	UES_IsValidArgumentalArea(unsigned char *def);
unsigned int	UES_HashString(unsigned char *string);
unsigned char	UES_IsLegitDefChar(unsigned char nchar);
unsigned char*	UES_ParseDef(unsigned char **curbufpos, size_t *sLen, size_t *sOutput, unsigned int *nlines);
unsigned char*	UES_ReadDef(void *fh, unsigned int *nlines);
char			UES_StrcmpCS(unsigned char *str1, unsigned char *str2);
unsigned char	UES_GetType(unsigned char *str);
ues_def_data_t*	UES_ConstructDef(unsigned char *ndef);
char*			fmt(char *s, ...);

#include "uesapi.h"
extern ues_core_api_t *c_api;

#endif //_UESCRIPT_